/*******************************************************************************
   @file    dev_Spi.h
   @author  H.M.Shim (elecage@gmail.com)
   @version 
   @date    2013. 7. 31.
   @brief   
  ******************************************************************************
  The MIT License (MIT)

Copyright (c) 2013 <copyright holders>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
  ******************************************************************************
  */



/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef DEV_SPI_H_
#define DEV_SPI_H_

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "devio.h"
#include "stm32f4xx_gpio.h"

#define NUM_SLAVE					4
/* Exported typedef -----------------------------------------------------------*/
typedef struct _Dev_Spi_flag{
	int8_t 			stat;				/**< @brief 장치의 상태 플래그 */
	uint16_t 		ms;					/**< @brief 마스터이면 0, slave이면 0x0008 */
	uint16_t 		address;			/**< @brief 읽고 쓰기를 할 주소 */
	uint16_t 		pol;				/**< @brief polarity */
	uint16_t		phase;				/**< @brief phase */
	int32_t			timeout;			/**< @brief 타임아웃 */
	int32_t			direction;			/**< @brief 방향, 2Line RxTx, 2Line Rx, 1Line Tx, 1Line Rx */
	int8_t			dataSize;			/**< @brief dataSize. 8 : 8bit, 16 : 16 bit */
	int16_t 		firstbit;
	GPIO_TypeDef*	csPort[NUM_SLAVE];
	uint16_t		csPin[NUM_SLAVE];
	uint16_t 		currentCs;
	SPI_InitTypeDef	SPI_InitStructure;
}__attribute__((packed))Dev_Spi_flag;

enum Dev_SPI_IOCTL_Param {
	DEV_SPI_SET_ADDR,					/**< @brief SPI 읽기/쓰기 주소 선택 */
	DEV_SPI_SET_SPEED,					/**< @brief SPI 클록 속도 설정 */
	DEV_SPI_SET_TIMEOUT,				/**< @brief SPI의 타임아웃 시간 설정 */
	DEV_SPI_SET_MASTER,					/**< @brief 장치를 SPI 마스터로 설정 */
	DEV_SPI_SET_SLAVE,					/**< @brief 장치를 SPI 슬레이브로 설정 */
	DEV_SPI_SET_PHASE_POLE,
	DEV_SPI_SET_DATASIZE,
	DEV_SPI_GET_ADDR,					/**< @brief SPI 읽기/쓰기 주소  가져오기*/
	DEV_SPI_GET_SPEED,					/**< @brief SPI 클록 속도  가져오기 */
	DEV_SPI_GET_TIMEOUT,				/**< @brief SPI의 타임아웃 시간 가져오기 */
	DEV_SPI_GET_MS,						/**< @brief 마스터인지 슬레이브인지 확인 */
	DEV_SPI_GET_PHASE_POLE,
	DEV_SPI_CLEAR_BUSY,					/**< @brief busy 신호를 클리어한다. */
};
/* Exported constants --------------------------------------------------------*/
#define NUM_SPI 					3


#define DEV_ARG_SPI_SET_ADDRESS		((const char*)"set_address")
#define DEV_ARG_SPI_GET_ADDRESS		((const char*)"get_address")
#define DEV_ARG_SPI_SET_MASTER		((const char*)"set_master")
#define DEV_ARG_SPI_SET_SLAVE		((const char*)"set_slave")
#define DEV_ARG_SPI_GET_MS			((const char*)"get_ms")
#define DEV_ARG_SPI_CLEAR_BUSY		((const char*)"clear_busy")
#define DEV_ARG_SPI_SET_POL_HIGH	((const char*)"pol_high")
#define DEV_ARG_SPI_SET_POL_LOW		((const char*)"pol_low")
#define DEV_ARG_SPI_SET_PHA_1		((const char*)"pha1")
#define DEV_ARG_SPI_SET_PHA_2		((const char*)"pha2")
#define DEV_ARG_SPI_DATA_16BIT		((const char*)"data_16")
#define DEV_ARG_SPI_DATA_8BIT		((const char*)"data_8")
#define MAX_SPI_BUF					128

#define SPI1_MISO_GPIO_CLK			RCC_AHB1Periph_GPIOB
#define SPI1_MISO_PIN				GPIO_Pin_4
#define SPI1_MISO_GPIO_PORT			GPIOB
#define SPI1_MISO_SOURCE			GPIO_PinSource4

#define SPI1_MOSI_GPIO_CLK			RCC_AHB1Periph_GPIOB
#define SPI1_MOSI_PIN				GPIO_Pin_5
#define SPI1_MOSI_GPIO_PORT			GPIOB
#define SPI1_MOSI_SOURCE			GPIO_PinSource5

#define SPI1_SCK_GPIO_CLK			RCC_AHB1Periph_GPIOB
#define SPI1_SCK_PIN				GPIO_Pin_3
#define SPI1_SCK_GPIO_PORT			GPIOB
#define SPI1_SCK_SOURCE				GPIO_PinSource3

#define SPI1_NSS_GPIO_CLK			RCC_AHB1Periph_GPIOA
#define SPI1_NSS_PIN				GPIO_Pin_15
#define SPI1_NSS_GPIO_PORT			GPIOA
#define SPI1_NSS_SOURCE				GPIO_PinSource15



#define SPI2_MISO_GPIO_CLK			RCC_AHB1Periph_GPIOB
#define SPI2_MISO_PIN				GPIO_Pin_14
#define SPI2_MISO_GPIO_PORT			GPIOB
#define SPI2_MISO_SOURCE			GPIO_PinSource14

#define SPI2_MOSI_GPIO_CLK			RCC_AHB1Periph_GPIOB
#define SPI2_MOSI_PIN				GPIO_Pin_15
#define SPI2_MOSI_GPIO_PORT			GPIOB
#define SPI2_MOSI_SOURCE			GPIO_PinSource15

#define SPI2_SCK_GPIO_CLK			RCC_AHB1Periph_GPIOB
#define SPI2_SCK_PIN				GPIO_Pin_13
#define SPI2_SCK_GPIO_PORT			GPIOB
#define SPI2_SCK_SOURCE				GPIO_PinSource13

#define SPI2_NSS_GPIO_CLK			RCC_AHB1Periph_GPIOB
#define SPI2_NSS_PIN				GPIO_Pin_12
#define SPI2_NSS_GPIO_PORT			GPIOB
#define SPI2_NSS_SOURCE				GPIO_PinSource12


#define SPI3_MISO_GPIO_CLK			RCC_AHB1Periph_GPIOC
#define SPI3_MISO_PIN				GPIO_Pin_13
#define SPI3_MISO_GPIO_PORT			GPIOC
#define SPI3_MISO_SOURCE			GPIO_PinSource13

#define SPI3_MOSI_GPIO_CLK			RCC_AHB1Periph_GPIOC
#define SPI3_MOSI_PIN				GPIO_Pin_12
#define SPI3_MOSI_GPIO_PORT			GPIOC
#define SPI3_MOSI_SOURCE			GPIO_PinSource12

#define SPI3_SCK_GPIO_CLK			RCC_AHB1Periph_GPIOC
#define SPI3_SCK_PIN				GPIO_Pin_14
#define SPI3_SCK_GPIO_PORT			GPIOC
#define SPI3_SCK_SOURCE				GPIO_PinSource14

#define SPI3_NSS_GPIO_CLK			RCC_AHB1Periph_GPIOA
#define SPI3_NSS_PIN				GPIO_Pin_4
#define SPI3_NSS_GPIO_PORT			GPIOA
#define SPI3_NSS_SOURCE				GPIO_PinSource14

#define SPI1_MOSI_AF				GPIO_AF_SPI1
#define SPI1_MISO_AF				GPIO_AF_SPI1
#define SPI1_SCK_AF					GPIO_AF_SPI1
#define SPI1_NSS_AF					GPIO_AF_SPI1

#define SPI2_MISO_AF				GPIO_AF_SPI2
#define SPI2_MOSI_AF				GPIO_AF_SPI2
#define SPI2_SCK_AF					GPIO_AF_SPI2
#define SPI2_NSS_AF					GPIO_AF_SPI2

#define SPI3_MISO_AF				GPIO_AF_SPI3
#define SPI3_MOSI_AF				GPIO_AF_SPI3
#define SPI3_SCK_AF					GPIO_AF_SPI3
#define SPI3_NSS_AF					GPIO_AF_SPI3

#define SPI1_CS1_GPIO_CLK		RCC_AHB1Periph_GPIOA
#define SPI1_CS1_GPIO_PIN		GPIO_Pin_15
#define SPI1_CS1_GPIO_PORT		GPIOA

#define SPI1_CS2_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI1_CS2_GPIO_PIN		GPIO_Pin_11
#define SPI1_CS2_GPIO_PORT		GPIOB

#define SPI1_CS3_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI1_CS3_GPIO_PIN		GPIO_Pin_10
#define SPI1_CS3_GPIO_PORT		GPIOB

#define SPI1_CS4_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI1_CS4_GPIO_PIN		GPIO_Pin_8
#define SPI1_CS4_GPIO_PORT		GPIOB

#define SPI2_CS1_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI2_CS1_GPIO_PIN		GPIO_Pin_12
#define SPI2_CS1_GPIO_PORT		GPIOB

#define SPI2_CS2_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI2_CS2_GPIO_PIN		GPIO_Pin_11
#define SPI2_CS2_GPIO_PORT		GPIOB

#define SPI2_CS3_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI2_CS3_GPIO_PIN		GPIO_Pin_10
#define SPI2_CS3_GPIO_PORT		GPIOB

#define SPI2_CS4_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI2_CS4_GPIO_PIN		GPIO_Pin_8
#define SPI2_CS4_GPIO_PORT		GPIOB

#define SPI3_CS1_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI3_CS1_GPIO_PIN		GPIO_Pin_12
#define SPI3_CS1_GPIO_PORT		GPIOB

#define SPI3_CS2_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI3_CS2_GPIO_PIN		GPIO_Pin_11
#define SPI3_CS2_GPIO_PORT		GPIOB

#define SPI3_CS3_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI3_CS3_GPIO_PIN		GPIO_Pin_10
#define SPI3_CS3_GPIO_PORT		GPIOB

#define SPI3_CS4_GPIO_CLK		RCC_AHB1Periph_GPIOB
#define SPI3_CS4_GPIO_PIN		GPIO_Pin_8
#define SPI3_CS4_GPIO_PORT		GPIOB

#define DEV_SPI_FLAG_MASTER			0x00000001
#define DEV_SPI_FLAG_SLAVE			0x00000002
#define DEV_SPI_FLAG_2LINE_FULL		0x00000100
#define DEV_SPI_FLAG_2LINE_RXONLY	0x00000200
#define DEV_SPI_FLAG_1LINE_TXONLY	0x00000400
#define DEV_SPI_FLAG_1LINE_RXONLY	0x00000800
#define DEV_SPI_FLAG_DATA_8BIT		0x00001000
#define DEV_SPI_FLAG_DATA_16BIT		0x00002000
#define DEV_SPI_FLAG_POL_HIGH		0x00010000
#define DEV_SPI_FLAG_POL_LOW		0x00020000
#define DEV_SPI_FLAG_PHASE_2		0x00040000
#define DEV_SPI_FLAG_PHASE_1		0x00080000
#define DEV_SPI_FLAG_MSB			0x00100000
#define DEV_SPI_FLAG_LSB			0x00200000


/* Exported macro ------------------------------------------------------------*/

/* Exported variables ------------------------------------------------------- */

/* Exported functions ------------------------------------------------------- */
int32_t registerDev_Spi(void);
int32_t dev_SpiOpen(const int8_t* devname, int32_t flags);
ssize_t dev_SpiWrite(int32_t dd, const void *buf, size_t n);
ssize_t	dev_SpiRead(int32_t dd, void *buf, size_t nbytes);
ssize_t dev_SpiIoctl(int32_t dd, int32_t request, void* data);
int32_t dev_SpiClose(int32_t dd);

void dev_SpiConfigInt(uint8_t portsource, EXTI_Config* config);

#ifdef USE_CMDLINE
int32_t dev_SpiOpenCmd(int32_t argc, int8_t *argv[]);
int32_t dev_SpiReadCmd(int32_t argc, int8_t *argv[]);
int32_t dev_SpiWriteCmd(int32_t argc, int8_t *argv[]);
int32_t dev_SpiIoctlCmd(int32_t argc, int8_t *argv[]);
int32_t dev_SpiCloseCmd(int32_t argc, int8_t *argv[]);
#endif /* USE_CMDLINE */
#endif /* DEV_SPI_H_ */
